root = getRootElement()
resource = getResourceRootElement(getThisResource())

--[[
	TODO-list
	minor: 
	- показывать хп на хпбаре
	- closerange-bug
	- wallbug	
	
	major:
	- границы
	- /hp (переключение "колонки")
	- базы
	- /restore
	- голосование (как сделать лучше?)
	- количество игроков записывать перед раундом
]]

data = {
	["main"] = {
		["status"] = "lobby";
		["swap"] = false;
		["pause"] = false;
	};
	["hud"] = {};
	["round"] = {
		["time"] = -1;
		["timer"] = -1;
		["readyCount"] = 0;
		["readyTimer"] = -1;
	};
	["counter"] = {
		["count"] = -1;
		["countTimer"] = -1;
	};
	["weapons"] = {
		[1] = {};
		[2] = {};
		[3] = {};
	};
	["teams"] = {
		[1] = {};
		[2] = {};
		[3] = {};
	};
	["lobby"] = {
		["spawn"] = {};
	};
	["select"] = {
		["position"] = {};
		["camera"] = {};
		["lookat"] = {};
	};
	["weaponNames"] = {};
	["map"] = {
		["id"] = 0;
		["spawns"] = {
			[1] = {};
			[2] = {};
		};
		["resource"] = -1;
		["interior"] = 0;
		
	};
	["other"] = {};
	["ids"] = {};
	["out"] = {};
}


-- UNIVERSAL FUNCTIONS

function explode(strText,strDelimiter) 
    local strTemp = "" 
    local tblOutput = {} 
    
    for intIndex=1,strText:len(),1 do 
        if (strText:sub(intIndex,intIndex + strDelimiter:len() - 1) == strDelimiter) then 
            table.insert(tblOutput,strTemp); strTemp = "" 
        else 
            strTemp = strTemp .. strText:sub(intIndex,intIndex) 
        end 
    end 
     
    if (strTemp ~= "") then table.insert(tblOutput,strTemp) end 
     
    return tblOutput 
end

function numberOrString(str)
	if str == 'true' then return true elseif str == 'false' then return false end
	local number = tonumber(str)
	if number then return number else return str end
end

function toboolean(var)
	local number = tonumber(var)
	if number then
		if number == 0 then return false else return true end
	else
		if var == 'false' then return false else return true end
	end
end

function isPlayerAdmin(player)
	if getPlayerIP(player) == '127.0.0.1' then return true end
	local admin = aclGetGroup ("Admin")
	local account = getPlayerAccount(player)
	if account then
		local accName = getAccountName(account)
		if isObjectInACLGroup("user."..accName, admin) then
			return true
		else
			return false
		end
	else
		return false
	end
end

function getTableCount(tbl)
	count = 0
	for i,v in pairs(tbl) do
		count = count + 1
	end
	return count
end

-- GAME FUNCTIONS

function nullPlayer(source)
	setElementData(source, "teamID", 1)
	setElementData(source, "status", "resload")
	setElementData(source, "selecting", false)
	setElementData(source, "kills", 0)
	setElementData(source, "deaths", 0)
	setElementData(source, "damage", 0)
	setElementData(source, "flashBlip", true)
end

function updateStatus(death)
	if death then
		if getTableCount(data["teams"][1]["players"]) == 0 then onRoundStop(2)
		elseif getTableCount(data["teams"][2]["players"]) == 0 then onRoundStop(1) end
	else
		if data["teams"][1]["hp"] > data["teams"][2]["hp"] then onRoundStop(1)
		elseif data["teams"][2]["hp"] > data["teams"][1]["hp"] then onRoundStop(2)
		elseif data["teams"][1]["hp"] == data["teams"][2]["hp"] then onRoundStop(-1) end
	end
end

function updatePlayersBeforeStartingRound()
	startRound()
	local players = getElementsByType("player")
	for i,player in ipairs(players) do
		if getElementData(player, "status") == "mapload" then
			spawn(player)
			triggerClientEvent(player, "onPlayerSkipMap", player)
		end
	end
end

function getConfig(conf)
	data["main"]["xml"] = xmlLoadFile(conf)
	local main = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "main", 0))
	local lobby = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "lobby", 0))
	local hud = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "hud", 0))
	local round = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "round", 0))
	local out = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "out", 0))
	local counter = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "counter", 0))
	local spawns = xmlNodeGetChildren(xmlFindChild(xmlFindChild(data["main"]["xml"], "lobby", 0), "spawns", 0))
	local weapons = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "weapons", 0))
	local teams = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "teams", 0))
	local select = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "select", 0))
	local bugs = xmlNodeGetChildren(xmlFindChild(data["main"]["xml"], "bugs", 0))

	for i,node in ipairs(main) do
		data["main"][xmlNodeGetName(node)] = numberOrString(xmlNodeGetValue(node))
	end
	for i,node in ipairs(round) do
		data["round"][xmlNodeGetName(node)] = numberOrString(xmlNodeGetValue(node))
	end
	for i,node in ipairs(out) do
		data["out"][xmlNodeGetName(node)] = numberOrString(xmlNodeGetValue(node))
	end
	for i,node in ipairs(counter) do
		data["counter"][xmlNodeGetName(node)] = numberOrString(xmlNodeGetValue(node))
	end
	for i,node in ipairs(bugs) do
		setGlitchEnabled(xmlNodeGetName(node), toboolean(xmlNodeGetValue(node)))
	end
	for i,node in ipairs(hud) do
		data["hud"][xmlNodeGetName(node)] = toboolean(xmlNodeGetValue(node))
	end
	for i,pNode in ipairs(weapons) do
		pNode = xmlNodeGetChildren(pNode)
		data["weapons"][i] = {}
		for j,node in ipairs(pNode) do
			data["weapons"][i][tonumber(string.sub(xmlNodeGetName(node), 2))] = numberOrString(xmlNodeGetValue(node))
		end
	end
	
	for i,pNode in ipairs(teams) do
		pNode = xmlNodeGetChildren(pNode)
		for j,node in ipairs(pNode) do
			data["teams"][i][xmlNodeGetName(node)] = numberOrString(xmlNodeGetValue(node))
		end
		if isElement(data["teams"][i]["team"]) then destroyElement(data["teams"][i]["team"]) end
		data["teams"][i]["team"] = createTeam(data["teams"][i]["name"])
		data["teams"][i]["hp"] = 0
		setTeamColor(data["teams"][i]["team"], data["teams"][i]["r"], data["teams"][i]["g"], data["teams"][i]["b"])
		setElementData(data["teams"][i]["team"], "status", 0)
		setElementData(data["teams"][i]["team"], "count", 0)
		setTeamFriendlyFire(data["teams"][i]["team"], data['main']['friendlyfire'])
	end
	
	for i,node in ipairs(lobby) do
		if node ~= spawns then data["lobby"][xmlNodeGetName(node)] = numberOrString(xmlNodeGetValue(node)) end
	end
	
	data["lobby"]["spawn"] = {}
	for i,node in ipairs(spawns) do
		local value = explode(xmlNodeGetValue(node), ",")
		data["lobby"]["spawn"][i] = {}
		data["lobby"]["spawn"][i]["x"] = tonumber(value[1])
		data["lobby"]["spawn"][i]["y"] = tonumber(value[2])
		data["lobby"]["spawn"][i]["z"] = tonumber(value[3])
	end
	
	for i,node in ipairs(select) do
		local nodeName = xmlNodeGetName(node)
		local value = explode(xmlNodeGetValue(node), ",")
		if type(data["select"][nodeName]) == 'table' then
			data["select"][nodeName]["x"] = tonumber(value[1])
			data["select"][nodeName]["y"] = tonumber(value[2])
			data["select"][nodeName]["z"] = tonumber(value[3])
		else
			data["select"][nodeName] = numberOrString(xmlNodeGetValue(node))
		end
	end
	for i,player in ipairs(getElementsByType('player')) do
		if getElementData(player, "status") ~= "resload" then
			triggerClientEvent(player, "onConfigUpdate", player, data)
			toSelectClass(player)
		end
	end

	for i=0,46 do data["weaponNames"][i] = getWeaponNameFromID(i) end
	setFPSLimit(data["main"]["fps"])
end

function toLobby(player)
	local lobbyPos = math.random(1, #data["lobby"]["spawn"])
	spawnPlayer(player, data["lobby"]["spawn"][lobbyPos]["x"],data["lobby"]["spawn"][lobbyPos]["y"],data["lobby"]["spawn"][lobbyPos]["z"],270,data["teams"][getElementData(player, "teamID")]["skin"],data["lobby"]["interior"],0)
	setElementInterior(player, data["lobby"]["interior"])
	setCameraInterior(player, data["lobby"]["interior"])
	setElementData(player, "status", "lobby")
	triggerClientEvent(root, "onPlayerWarpToLobby", root, player)
end

function toSelectClass(player)
	triggerClientEvent(player, "onPlayerRequestClass", player)
	triggerClientEvent(player, "onPlayerClassChange", player, getElementData(player, "teamID"))
	spawnPlayer(player, data["select"]["position"]["x"],data["select"]["position"]["y"],data["select"]["position"]["z"],270,data["teams"][getElementData(player, "teamID")]["skin"],data["select"]["interior"],getElementData(player, "id"))
	setCameraInterior(player, data["select"]["interior"])
	fadeCamera(player, true)
	setCameraTarget(player, player)
	setCameraMatrix(player, data["select"]["camera"]["x"],data["select"]["camera"]["y"],data["select"]["camera"]["z"], data["select"]["lookat"]["x"],data["select"]["lookat"]["y"],data["select"]["lookat"]["z"])
	bindKey(player, "arrow_r", "down", nextClass, player)
	bindKey(player, "arrow_l", "down", prevClass, player)
	bindKey(player, "enter", "down", selectClass, player)
	toggleAllControls(player, false, true, false)
	setElementData(player, "status", "selecting")
end

function toSpectate(player, specPlayer)
	local x,y,z = getElementPosition(specPlayer)
	setElementAlpha(player, 0)
	setCameraTarget(player, specPlayer)
	setCameraInterior(player, getElementInterior(specPlayer))
	setElementInterior(player, getElementInterior(specPlayer))
	setElementData(player, "spectatePlayer", specPlayer)
	setElementFrozen(player, true)
	setElementPosition(player, x, y, z+50)
end

function toplayer(str)
	local players = getElementsByType("player")
	local id = tonumber(str)
	if id and data["ids"][id] then	
		return data["ids"][id]
	else
		for i, player in ipairs(players) do
			local x = string.find(getPlayerName(player), str)
			if x == 0 then return player end
		end
	end
	return false
end




function startMap(id, mapName, resource)
	local mapMeta = xmlLoadFile(":"..mapName.."/meta.xml")
	local mapSettings = xmlNodeGetChildren(xmlFindChild(mapMeta, "settings", 0))
	data["map"]["interior"] = 0
	for key,value in ipairs(mapSettings) do
		local nodeName = string.lower(string.sub(xmlNodeGetAttribute(value, "name"),2))
		local nodeValue = xmlNodeGetAttribute(value, "value")
		if nodeName == "time" then 
			nodeValue = explode(nodeValue, ":")
			data["map"]["hour"] = tonumber(nodeValue[1])
			data["map"]["minute"] = tonumber(nodeValue[2])
		else
			data["map"][nodeName] = numberOrString(string.sub(nodeValue,3,string.len(nodeValue)-2))
		end
	end
	data["round"]["readyCount"] = 0
	for i,player in ipairs(getElementsByType("player")) do
		if getElementData(player, "status") == "lobby" then
			data["round"]["readyCount"] = data["round"]["readyCount"] + 1
			setElementData(player, "status", "mapload")
			triggerClientEvent(player, "onPlayerMapLoading", player, mapName, id)
		end
	end
	startResource(resource)
	data["map"]["central"] = getElementByID("Central_Marker (1)")
	data["map"]["resource"] = resource
	data["map"]["id"] = id
	data["main"]["status"] = "loading"
	data["round"]["readyTimer"] = setTimer(updatePlayersBeforeStartingRound, data["main"]["timeout"]*1000, 1)
	for i=1,2 do data["map"]["spawns"][i] = getElementsByType("Team"..i) end
end

function fromRound(player)
	
end

function toRound(player)
	local team = getElementData(player, "teamID")
	local spawn = team
	local id = getElementData(player, "id")

	if data["main"]["swap"] then if team == 1 then spawn = 2 else spawn = 1 end end
	data["teams"][team]["players"][id] = player
	data["teams"][3]["players"][id] = player
	data["teams"][team]["hp"] = data["teams"][team]["hp"] + 100
	spawn = data["map"]["spawns"][spawn][getTableCount(data["teams"][team]["players"])]
	setElementData(data["teams"][team]["team"], "count", getTableCount(data["teams"][team]["players"]))
	setElementData(data["teams"][team]["team"], "hp", data["teams"][team]["hp"])
	removePedFromVehicle(player)
	setElementPosition(player, getElementData(spawn, "posX"), getElementData(spawn, "posY"), getElementData(spawn, "posZ"))
	setElementRotation(player, getElementData(spawn, "rotX"), getElementData(spawn, "rotY"), getElementData(spawn, "rotZ"))
	setElementInterior(player, data["map"]["interior"])
	setElementData(player, "status", "playing")
	setElementFrozen(player, false)
	takeAllWeapons(player)
end

function startRound()
	data["main"]["status"] = "starting"
	data["counter"]["count"] = data["counter"]["default"]
	for i=1,3 do
		data["teams"][i]["hp"] = 0
		data["teams"][i]["players"] = {}
		setElementData(data["teams"][i]["team"], "hp", 0)
	end
	if data["main"]["autoswap"] then data["main"]["swap"] = not data["main"]["swap"] end
	for i,player in ipairs(getElementsByType("player")) do
		if getElementData(player, "status") == "ready" then
			if getElementData(player, "teamID") == 3 then
				setElementData(player, "status", "spectating")
				setElementPosition(player, getElementData(data["map"]["central"], "posX"), getElementData(data["map"]["central"], "posY"), getElementData(data["map"]["central"], "posZ"))
			else
				toRound(player)
				toggleAllControls(player, false, true, false)
			end
			triggerClientEvent(player, "onRoundRequestStarting", player, data["map"]["id"])
			setCameraMatrix(player, getElementData(data["map"]["central"], "posX"), getElementData(data["map"]["central"], "posY"), getElementData(data["map"]["central"], "posZ")+120, getElementData(data["map"]["central"], "posX"), getElementData(data["map"]["central"], "posY"), getElementData(data["map"]["central"], "posZ"))
		end
	end
	if isTimer(data["round"]["readyTimer"]) then killTimer(data["round"]["readyTimer"]) end
	data["counter"]["timer"] = setTimer(onRoundStarting, 1000, 0)
end

function spawn(player)
	if isElement(player) then
		setElementData(player, "spectatePlayer", nil)
		setCameraTarget(player, player)
		setElementFrozen(player, false)
		setElementAlpha(player, 255)
		toggleAllControls(player, true, true, false)
		fadeCamera(player, true)
		local skills = {69,70,71,72,73,74,75,76,77,78,79,160,229,230}
		for key,value in pairs(skills) do setPedStat(player, value, 999) end
		if (data["main"]["status"] == "playing") or (data["main"]["status"] == "starting") then 
			local players = getPlayersInGame(getElementData(player, "teamID"))
			setElementData(player, "status", "spectating")
			if getTableCount(players) ~= 0 then toSpectate(player, getRandomElement(players)) end
			triggerClientEvent(player, "onRoundStart", player, data["round"]["time"])
		else 
			toLobby(player) 
		end
	end
end

function getPlayersInGame(team)
	return data["teams"][team]["players"]
end

function getRandomElement(tbl)
	local tmp = {}
	local j = 1
	for i, element in pairs(tbl) do
		tmp[j] = element
		j = j + 1
	end
	return tmp[math.random(1, #tmp)]
end

function giveWeapons(weapons)
	takeAllWeapons(source)
	for key,value in pairs(weapons) do giveWeapon(source, key, value) end
end

function class(player, team)
	setElementData(player, "teamID", team)
	setElementModel(player, data["teams"][team]["skin"])
	triggerClientEvent(player, "onPlayerClassChange", player, team)
end


-- BINDS

function nextSpectator(player)
	if (getElementData(player, "status") ~= 'spectating') then return false end
	local players = getPlayersInGame(getElementData(player, "teamID"))
	local currentTeammate = -1

	local tmpPlayers = {}
	local j = 1
	for i, player in pairs(players) do
		tmpPlayers[j] = player
		j = j + 1
	end

	if #tmpPlayers ~= 0 then
		for i, teammate in ipairs(tmpPlayers) do 
			if teammate == getElementData(player, "spectatePlayer") then 
				currentTeammate = i 
				break 
			end 
		end
		if currentTeammate == #tmpPlayers then 
			toSpectate(player, tmpPlayers[1]) 
		else 
			toSpectate(player, tmpPlayers[currentTeammate+1])
		end
	end
end

function backSpectator(player)
	if (getElementData(player, "status") ~= 'spectating') then return false end
	local players = getPlayersInGame(getElementData(player, "teamID"))
	local currentTeammate = -1
	local tmpPlayers = {}
	local j = 1
	for i, player in pairs(players) do
		tmpPlayers[j] = player
		j = j + 1
	end

	if #tmpPlayers ~= 0 then
		for i, teammate in ipairs(tmpPlayers) do 
			if teammate == getElementData(player, "spectatePlayer") then 
				currentTeammate = i 
				break 
			end 
		end
		if currentTeammate == 1 then 
			toSpectate(player, tmpPlayers[#tmpPlayers]) 
		else 
			toSpectate(player, tmpPlayers[currentTeammate-1])
		end
	end
end

function isSelectingSkin(source) 
	if data['main']['status'] == "lobby" then
		nextClass(source)
		selectClass(source)
		triggerClientEvent(root, "onPlayerWarpToLobby", root, player)
	end
end

function nextClass(player)
	local team = getElementData(player, "teamID")
	if team == 3 then team = 1 else team = team+1 end
	class(player, team)
end

function prevClass(player)
	local team = getElementData(player, "teamID")
	if team == 1 then team = 3 else team = team-1 end
	class(player, team)
end

function selectClass(player)
	unbindKey(player, "arrow_r", "down", nextClass, player)
	unbindKey(player, "arrow_l", "down", prevClass, player)
	unbindKey(player, "enter", "down", selectClass, player)
	triggerClientEvent(player, "onPlayerClassSelected", player, getElementData(player, "teamID"))
	setPlayerTeam(player, data["teams"][getElementData(player, "teamID")]["team"])
	setElementModel(player, data["teams"][getElementData(player, "teamID")]["skin"])
	setElementDimension(player, 0)
	toggleAllControls(player, true, true, false)
	spawn(player)
end

function flashBlip(thePlayer)
	if getElementData(thePlayer, "flashBlip") and getElementData(thePlayer, "status") == "playing" then
		local players = getPlayersInTeam(getPlayerTeam(thePlayer))
		for i, player in ipairs(players) do
			triggerClientEvent(player, "toFlashBlip", player, getPlayerName(thePlayer))
			outputChatBox("#FF0000"..getPlayerName(thePlayer).."#FFFFFF просит о помощи!", player, 0,0,0,true)
		end
		setElementData(thePlayer, "flashBlip", false)
		setTimer(setElementData, 30000, 1, thePlayer, "flashBlip", true)
	end
end


-- ADMINISTRATION COMMANDS

function arena(player, cmd, id)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	if data['main']['status'] ~= 'lobby' then return outputChatBox("Карта уже запущена!", player) end
	--if countPlayersInTeam(data['teams'][1]["team"]) == 0 or countPlayersInTeam(data['teams'][2]["team"]) == 0 then return outputChatBox("В одной из команд недостаточно игроков для начала игры", player) end
	
	local mapName = "arena_"..id
	local resource = getResourceFromName(mapName)
	if resource then
		startMap(id, mapName, resource)
	else
		outputChatBox("Такой карты не существует!", player)
	end
end

function config(player, cmd, conf)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	local configFile = "configs/"..conf..".xml"
	if not fileExists (configFile) then return outputChatBox("Такого конфига не существует!", player) end
	getConfig(configFile)
end

function swap(player)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	data["main"]["swap"] = not data["main"]["swap"]
end

function resetTeamScore(player)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	for i=1,2 do setElementData(data["teams"][i]["team"], "status", 0) end
	for i,player in ipairs(getElementsByType("player")) do
		if (getElementData(player, "status") ~= "resload") then	
			setElementData(player, "damage", 0)
			setElementData(player, "kills", 0)
			setElementData(player, "deaths", 0)
		end
	end
end

function setTeamScore(player, cmd, team, score)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	team = tonumber(team)
	score = tonumber(score)
	if (not team) or (not score) or ((team ~= 1) and (team ~= 2)) then return outputChatBox("/score (1-2) [value]", player) end
	setElementData(data["teams"][team]["team"], "status", score)
end

function setTeamTitle(player, cmd, team, ...)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	team = tonumber(team)
	name = table.concat({...}, " ")
	if (not team) or (not name) or ((team ~= 1) and (team ~= 2)) then return outputChatBox("/name (1-2) [value]", player) end
	setTeamName(data["teams"][team]["team"], name)
	data["teams"][team]["name"] = name
end

function breakRound(player)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	
	if data["main"]["status"] ~= 'lobby' and data["main"]["status"] ~= 'stopping' then
		if isTimer(data["counter"]["timer"]) then killTimer(data["counter"]["timer"])	end
		if isTimer(data["round"]["timer"]) then killTimer(data["round"]["timer"]) end
		if isTimer(data["round"]["readyTimer"]) then killTimer(data["round"]["readyTimer"]) end
		if isElement(data["map"]["radar"]) then 
			destroyElement(data["map"]["radar"]) 
			destroyElement(data["map"]["rectangle"]) 
		end
		stopResource(data["map"]["resource"])
		data["main"]["status"] = "lobby"
		
		if isElement(data["map"]["polygon"]) then
			for i, radar in pairs(data["map"]["radars"]) do destroyElement(radar) end
			destroyElement(data["map"]["polygon"])
		end
		
		for i,player in ipairs(getElementsByType("player")) do
			if (getElementData(player, "status") == "playing") or (getElementData(player, "status") == "spectating") then	
				spawn(player)
				triggerClientEvent(player, "onRoundEnd", player)
			end
		end
	end
end
		
function pauseRound(player)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	if data["main"]["status"] == "playing" then
		data['main']['pause'] = not data['main']['pause']
		triggerClientEvent(root, "onRoundPause", root, data['main']['pause'])
		if data['main']['pause'] then
			for i,player in ipairs(getElementsByType("player")) do
				if (getElementData(player, "status") == "playing") or (getElementData(player, "status") == "spectating") then	
					toggleAllControls(player, false, true, false)
					playSoundFrontEnd(player, 46)
				end
			end
			killTimer(data["round"]["timer"])
		else
			for i,player in ipairs(getElementsByType("player")) do
				if (getElementData(player, "status") == "playing") or (getElementData(player, "status") == "spectating") then	
					toggleAllControls(player, true, true, false)
					playSoundFrontEnd(player, 46)
				end
			end
			data["round"]["timer"] = setTimer(onRoundPlaying, 1000, 0)
		end
	end
end

function addPlayer(player, cmd, id)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	local thePlayer = toplayer(id)
	if not thePlayer then return outputChatBox("Такого игрока не существует (/add [id/name])!", player) end
	if (data["main"]["status"] == "playing") and (getElementData(thePlayer, "status") == "spectating") and (getElementData(thePlayer, "teamID") ~= 3) then
		setElementData(thePlayer, "spectatePlayer", nil)
		setCameraTarget(thePlayer, thePlayer)
		setElementAlpha(thePlayer, 255)
		toggleAllControls(thePlayer, true, true, false)
		toLobby(thePlayer)
		toRound(thePlayer)
		setCameraTarget(thePlayer, thePlayer)
		setElementHealth(thePlayer, 100.0)
		outputChatBox(getPlayerName(thePlayer).. " добавлен в игру")
		triggerClientEvent(thePlayer, "onRoundStart", thePlayer, data["round"]["time"])
	end
end

function removePlayer(player, cmd, id)
	if not isPlayerAdmin(player) then return outputChatBox("Вы не администратор!", player) end
	local thePlayer = toplayer(id)
	local team = getElementData(thePlayer, "teamID")
	if not thePlayer then return outputChatBox("Такого игрока не существует (/remove [id/name])!", player) end
	if (data["main"]["status"] == "playing") and (team ~= 3) then
		data["teams"][team]["hp"] = data["teams"][team]["hp"] - getElementHealth(thePlayer)
		data["teams"][team]["players"] = removeElementFromTable(data["teams"][team]["players"], getElementData(thePlayer, "id"))
		data["teams"][3]["players"] = removeElementFromTable(data["teams"][3]["players"], getElementData(thePlayer, "id"))
		setElementData(data["teams"][team]["team"], "count", getTableCount(data["teams"][team]["players"]))
		outputChatBox(getPlayerName(thePlayer).. " удалён из игры")
		spawn(thePlayer)
		updateStatus(true)
	end
end


-- PLAYER COMMANDS

function kill(player)
	if ((data["main"]["status"] == "playing") or (data["main"]["status"] == "lobby")) then
		killPed(player)
	end
end


-- CUSTOM EVENTS

function onRoundStarting()
	for i,player in ipairs(getElementsByType("player")) do 
		if data["counter"]["count"] > 0 then playSoundFrontEnd(player, 44) else	playSoundFrontEnd(player, 45) end
	end
	if data["counter"]["count"] == 0 then onRoundStart() end
	data["counter"]["count"] = data["counter"]["count"] - 1
end

function onRoundPlaying()
	data["round"]["time"] = data["round"]["time"] - 1
	if data["round"]["time"] == 0 then updateStatus() end
end

function onRoundStart()
	data["round"]["time"] = data["round"]["default"]
	data["round"]["timer"] = setTimer(onRoundPlaying, 1000, 0)
	data["main"]["pause"] = false
	data["main"]["status"] = "playing"
	local area = getElementsByType("Anti_Rush_Point")
	local maxx = 0
	local bounds_x = { }
	local bounds_y = { }
	local bounds = { }

	for k, val in ipairs(getElementsByType("Anti_Rush_Point")) do
		if(isElement(val)) then
				bounds_x[k], bounds_y[k] = getElementPosition(val)
				if(k == 1) then
					bounds[k], bounds[k+1] = bounds_x[k], bounds_y[k]
					idx1 = 3
					idx2 = 4
				else
					bounds[idx1] = bounds_x[k]
					bounds[idx2] = bounds_y[k]
					idx1 = idx1 + 2
					idx2 = idx2 + 2
				end
				maxx = maxx + 1
		end
	end
	if (maxx > 1) then
		local k_plus_1 = 0
		local j = 1
		data["map"]["radars"] = {}
		for k = 1, maxx do
			k_plus_1 = k + 1
			if(k_plus_1 > maxx) then k_plus_1 = 1 end
			distance = math.floor(getDistanceBetweenPoints2D(bounds_x[k], bounds_y[k], bounds_x[k_plus_1], bounds_y[k_plus_1]))
			delta_x = (bounds_x[k_plus_1] - bounds_x[k]) / distance
			delta_y = (bounds_y[k_plus_1] - bounds_y[k]) / distance
			for i = 0, distance/10 do
				data["map"]["radars"][j] = createRadarArea(bounds_x[k] + (10*i) * delta_x, bounds_y[k] + (10*i) * delta_y, 15,15, 210, 80, 0, 225)
				j = j + 1
			end
		end
		data["map"]["polygon"] = createColPolygon (bounds_x[1], bounds_y[1], unpack(bounds))
		addEventHandler("onColShapeHit", data["map"]["polygon"], function(player) triggerClientEvent(player, "onBoundsEnter", data["map"]["polygon"]) end)
		addEventHandler("onColShapeLeave", data["map"]["polygon"], function(player) triggerClientEvent(player, "onBoundsLeave", data["map"]["polygon"]) end)
	end
	for i,player in ipairs(getElementsByType("player")) do
		if getElementData(player, "status") == "playing" then	
			setCameraTarget(player, player)
			toggleAllControls(player, true, true, false)
			setElementHealth(player, 100.0)
			triggerClientEvent(player, "onRoundStart", player)
		elseif getElementData(player, "status") == "spectating" then	
			local players = getPlayersInGame(3)
			if getTableCount(players) ~= 0 then toSpectate(player, getRandomElement(players)) end
			triggerClientEvent(player, "onRoundStart", player)
		end
	end
	killTimer(data["counter"]["timer"])
end

function onRoundStop(winner)
	data["main"]["status"] = "stopping"
	if winner ~= -1 then setElementData(data["teams"][winner]["team"], "status", getElementData(data["teams"][winner]["team"], "status")+1) end
	local players = getElementsByType("player")
	if isElement(data["map"]["polygon"]) then
		for i, radar in pairs(data["map"]["radars"]) do destroyElement(radar) end
		destroyElement(data["map"]["polygon"])
	end
		
	for i,player in ipairs(players) do
		if (getElementData(player, "status") == "playing") or (getElementData(player, "status") == "spectating") then
			triggerClientEvent(player, "onRoundStop", player, winner)
			toggleAllControls(player, false, true, false)
			setGameSpeed(0.01)
		end
	end
	
	setTimer(function()
		setGameSpeed(1.0)
		local players = getElementsByType("player")
		for i,player in ipairs(players) do
			if (getElementData(player, "status") == "playing") or (getElementData(player, "status") == "spectating") then
				fadeCamera(player, false, 1.0)
			end
		end
	end, 7000, 1)
	
	setTimer(function()
		local players = getElementsByType("player")
		for i,player in ipairs(players) do
			if (getElementData(player, "status") == "playing") or (getElementData(player, "status") == "spectating") then
				spawn(player)
			end
		end
		stopResource(data["map"]["resource"])
		data["main"]["status"] = "lobby"
	end, 8000, 1)
	killTimer(data["round"]["timer"])
end

function onPlayerReady()
	outputChatBox("#F78145"..getPlayerName(source).."#FFFFFF зашёл на сервер", root,0,0,0,true)
	nullPlayer(source)
	local i = 1
	while true do
		if data["ids"][i] == nil then
			data["ids"][i] = source 
			setElementData(source, "id", i)
			break
		end
		i = i + 1
	end
	bindKey(source, "r", "down", reloadPedWeapon, source)
	bindKey(source, "q", "down", nextSpectator, source)
	bindKey(source, "e", "down", backSpectator, source)
	bindKey(source, "f4", "down", isSelectingSkin, source)
	bindKey(source, "pause", "down", "pause", "")
	bindKey(source, "end", "down", "break", "")
	bindKey(source, "num_4", "down", "flash", "")
	triggerClientEvent(source, "onConfigUpdate", source, data)
	toSelectClass(source)
end

function onPlayerReadyForMap()
	if data["main"]["status"] == "loading" then
		setElementData(source, "status", "ready")
		data["round"]["readyCount"] = data["round"]["readyCount"] - 1
		if (data["round"]["readyCount"] == 0) then startRound() end
	end
end

-- NATIVE EVENTS

function onServerReady()
	aclReload()
	setGameType("AAD Rumble")
	local dxscoreboard = getResourceFromName("dxscoreboard")
	if dxscoreboard then 
		exports.dxscoreboard:scoreboardAddColumn("id",root,30)
		exports.dxscoreboard:scoreboardAddColumn("status",root,70)
		exports.dxscoreboard:scoreboardAddColumn("kills",root,30)
		exports.dxscoreboard:scoreboardAddColumn("deaths",root,30)
		exports.dxscoreboard:scoreboardAddColumn("damage",root,50)
		exports.dxscoreboard:scoreboardAddColumn("fps",root,20)
	end
	for i,player in ipairs(getElementsByType('player')) do setElementData(player, "status", "resload") end
	setGameSpeed(1.0)
	setTime(12,0)
	setMinuteDuration(9999999999999999)
	getConfig("configs/league.xml")
end

function onPlayerDamage(attacker, weapon, bodypart, loss)
	if (data['main']['status'] == "playing") then
		local team = getElementData(source, "teamID")
		if getElementData(source, "status") == "playing" then 
			data["teams"][team]["hp"] = data["teams"][team]["hp"] - loss 
			setElementData(data["teams"][team]["team"], "hp", data["teams"][team]["hp"])
		end
		if attacker and isElement(attacker) and attacker ~= source and getElementType(attacker) == 'player' then
			playSoundFrontEnd(attacker, 32)
			setElementData(attacker, "damage", string.format("%.f", tonumber(getElementData(attacker, "damage")) + loss))
		end
		playSoundFrontEnd(source, 101)
	end
end

function onPlayerExit()
	outputChatBox("#8F3D14"..getPlayerName(source).."#FFFFFF вышел с сервера", root,0,0,0,true)
	local id = getElementData(source, "id")
	if ((data["main"]["status"] == "playing") or (data["main"]["status"] == "starting")) and getElementData(source, "status") == "playing" then 
		local allPlayers = getElementsByType("player")
		for i,player in ipairs(allPlayers) do
			if getElementData(player, "spectatePlayer") == source then
				local players = getPlayersInGame(getElementData(player, "teamID"))
				if getTableCount(players) ~= 0 then toSpectate(player, getRandomElement(players)) end
			end
		end
		local team = getElementData(source, "teamID")
		data["teams"][team]["players"] = removeElementFromTable(data["teams"][team]["players"], id)
		data["teams"][3]["players"] = removeElementFromTable(data["teams"][3]["players"], id)
		updateStatus(true)
	end
	if getElementData(source, "status") ~= "resload" then 
		data["ids"][id] = nil 
	end
	if getElementData(source, "status") == "mapload" then
		data["round"]["readyCount"] = data["round"]["readyCount"] - 1
	end
end

function onPlayerJoin()
	nullPlayer(source)
end

function removeElementFromTable(tbl, key)
	local tmp = {}
	for i, value in pairs(tbl) do
		if i ~= key then
			tmp[i] = value
		end
	end
	return tmp
end

function onPlayerDeath(ammo, killer)
	local team = getElementData(source, "teamID")
	local loss = getElementHealth(source)
	if (data["main"]["status"] == "playing") then 
		data["teams"][team]["hp"] = data["teams"][team]["hp"] - loss
		setElementData(data["teams"][team]["team"], "hp", data["teams"][team]["hp"])
		if killer and isElement(killer) and killer ~= source and getElementType(killer) == 'player' then
			setElementData(killer, "kills", getElementData(killer, "kills")+1)
			setElementData(killer, "damage", string.format("%.f", tonumber(getElementData(killer, "damage")) + loss))
		end
		
		data["teams"][team]["players"] = removeElementFromTable(data["teams"][team]["players"], getElementData(source, "id"))
		data["teams"][3]["players"] = removeElementFromTable(data["teams"][3]["players"], getElementData(source, "id"))
		setElementData(data["teams"][team]["team"], "count", getTableCount(data["teams"][team]["players"]))
		setElementData(source, "deaths", getElementData(source, "deaths")+1)
		setElementData(source, "status", "spectating")
		updateStatus(true)
		setTimer(function(source) 	
			if (data["main"]["status"] == "playing") then
				local allPlayers = getElementsByType("player")
				for i,player in ipairs(allPlayers) do
					if getElementData(player, "spectatePlayer") == source then
						local players = getPlayersInGame(getElementData(player, "teamID"))
						if getTableCount(players) ~= 0 then toSpectate(player, getRandomElement(players)) end
					end
				end
			end
			local players = getPlayersInGame(team)
			if getTableCount(players) ~= 0 then toSpectate(source, getRandomElement(players)) end
		end, 2000, 1, source)
	else
		setTimer(spawn, 2000, 1, source)
	end
end

function onVehicleDestroy()
	setTimer(respawnVehicle, 5000, 1, source)
end


-- CUSTOM EVENT HANDLERS
addEvent("onPlayerReady", true)
addEvent("onPlayerReadyForMap", true)
addEvent("giveWeapons", true)
addEventHandler("giveWeapons", root, giveWeapons)
addEventHandler("onPlayerReady", root, onPlayerReady)
addEventHandler("onPlayerReadyForMap", root, onPlayerReadyForMap)

-- NATIVE EVENT HANDLERS
addEventHandler("onResourceStart", resource, onServerReady)
addEventHandler("onPlayerWasted", root, onPlayerDeath)
addEventHandler("onPlayerDamage", root, onPlayerDamage)
addEventHandler("onPlayerQuit", root, onPlayerExit)
addEventHandler("onVehicleExplode", root, onVehicleDestroy)
addEventHandler("onPlayerJoin", root, onPlayerJoin)

-- PLAYER COMMAND HANDLERS
addCommandHandler("kill", kill)
addCommandHandler("flash", flashBlip)

-- ADMINISTRATION COMMAND HANDLERS
addCommandHandler("break", breakRound)
addCommandHandler("pause", pauseRound)
addCommandHandler("add", addPlayer)
addCommandHandler("remove", removePlayer)
addCommandHandler("arena", arena)
addCommandHandler("swap", swap)
addCommandHandler("reset", resetTeamScore)
addCommandHandler("name", setTeamTitle)
addCommandHandler("score", setTeamScore)
addCommandHandler("config", config)